/*
 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
// NOLINTBEGIN(cppcoreguidelines-avoid-goto)
// NOLINTNEXTLINE(readability-function-size)
inline VerificationStatus AbstractInterpret(VerificationContext& verifCtx, const uint8_t* pc, EntryPointType codeType) {
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wvoid-ptr-dereference"
#pragma clang diagnostic ignored "-Wgnu-label-as-value"
#elif defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#endif
    constexpr std::size_t DISPATCH_TABLE_HANDLER_NAMES_SIZE = <%= Panda::dispatch_table.handler_names.size %>;
    std::array<const void*, DISPATCH_TABLE_HANDLER_NAMES_SIZE> dispatchTable{
% Panda::dispatch_table.handler_names.each do |name|
        &&HANDLE_<%= name %>,
% end
    };

    AbsIntInstructionHandler handler(verifCtx, pc, codeType);
    uint8_t secondaryOpcode;

    if (!handler.IsPrimaryOpcodeValid()) {
        LOG(ERROR, VERIFIER) << "Incorrect opcode";
        return VerificationStatus::ERROR;
    }
    goto* dispatchTable[handler.GetPrimaryOpcode()];

% Panda::instructions.each do |i|
%   mnemonic = i.mnemonic.split('.').map { |p| p == '64' ? 'Wide' : p.capitalize }.join
HANDLE_<%= i.handler_name %>:
% if i.namespace != 'core'
#ifdef PANDA_WITH_<%= i.namespace.upcase %>
% end
% if i.namespace == 'ecmascript'
    LOG(ERROR, VERIFIER) << "<%= i.namespace %> verification is not yet supported";
    return VerificationStatus::ERROR;
% else
    if (!handler.template Handle<%= mnemonic %><BytecodeInstructionSafe::Format::<%= i.format.pretty.upcase %>>()) {
        return handler.GetStatus();
    }
% end
    goto COMMON_BODY;
% if i.namespace != 'core'
#endif // PANDA_WITH_<%= i.namespace.upcase %>
% end
% end
COMMON_BODY:
{
    if (!handler.IsPrimaryOpcodeValid()) {
        LOG(ERROR, VERIFIER) << "Incorrect opcode";
        return VerificationStatus::ERROR;
    }
    goto* dispatchTable[handler.GetPrimaryOpcode()];    
}
HANDLE_INVALID:
    LOG(ERROR, VERIFIER) << "Incorrect opcode";
    return VerificationStatus::ERROR;
% Panda::prefixes.each do |p|
HANDLE_<%= p.handler_name %>:
    secondaryOpcode = handler.GetSecondaryOpcode();
    LOG(DEBUG, VERIFIER) << "ABSINT: Prefix subdispatch: " << "<%= p.name %>, " << static_cast<int32_t>(secondaryOpcode);
    // NOLINTNEXTLINE(readability-magic-numbers)
    if (secondaryOpcode > <%= Panda::dispatch_table.secondary_opcode_bound(p) %> ) {
        LOG(ERROR, VERIFIER) << "Incorrect opcode";
        return VerificationStatus::ERROR;
    }
    // NOLINTNEXTLINE(readability-magic-numbers)
    goto *dispatchTable[<%= Panda::dispatch_table.secondary_opcode_offset(p) %> + secondaryOpcode];
% end

#if defined(__clang__)
#pragma clang diagnostic pop
#elif defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
}

// NOLINTEND(cppcoreguidelines-avoid-goto)
